import { useEffect, useRef, useState, lazy, Suspense } from 'react'
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
import { registerMountPoint, mount as mountPlugin, createEventBus } from '@bai-hu/plugin-host-web'
import type { PluginManifest } from '@bai-hu/plugin-registry-types'
import type { AppEvents } from '@bai-hu/plugin-sdk'

import { Layout } from './components/Layout'
import { ErrorBoundary } from './components/ErrorBoundary'
import { LoadingSpinner } from './components/ui/LoadingSpinner'
import { ConfigurationModal } from './components/ConfigurationModal'

// Lazy load page components
const Dashboard = lazy(() => import('./pages/Dashboard').then(module => ({ default: module.Dashboard })))
const PluginManagement = lazy(() => import('./pages/PluginManagement').then(module => ({ default: module.PluginManagement })))
const PluginDetail = lazy(() => import('./pages/PluginDetail').then(module => ({ default: module.PluginDetail })))
const AdminPanel = lazy(() => import('./pages/AdminPanel').then(module => ({ default: module.AdminPanel })))
const AuditPage = lazy(() => import('./pages/AuditPage').then(module => ({ default: module.AuditPage })))

// Preload critical routes using dynamic import manager
const preloadRoutes = () => {
  // Note: We don't need to preload these since they're already lazy loaded by React
  // The lazy() calls handle the dynamic imports properly
  console.log('Route preloading disabled - using React lazy loading instead')
}

type MarketItem = { name: string; manifest: string; enabled: boolean }

type UIMap = Record<string, () => JSX.Element>

function getIdFromName(name: string) {
  const parts = name.split('/')
  return parts[parts.length - 1]
}





export default function App() {
  const [market, setMarket] = useState<MarketItem[]>([])
  const mountRef = useRef<HTMLDivElement | null>(null)
  const [pluginUIs, setPluginUIs] = useState<UIMap>({})
  const [editing, setEditing] = useState<string | null>(null)
  const [formValue, setFormValue] = useState<Record<string, any>>({})
  const [formSchema, setFormSchema] = useState<any>(null)
  const [theme, setTheme] = useState<'light' | 'dark'>('light')
  const eventBus = useRef(createEventBus<AppEvents>()).current
  const [rescanLoading, setRescanLoading] = useState(false)
  const [apiKey, setApiKey] = useState<string>(localStorage.getItem('admin-api-key') || '')
  const [authError, setAuthError] = useState<string | null>(null)

  // Initialize global error handler and preload routes
  useEffect(() => {
    // Error handler is automatically initialized when imported
    console.log('Global error handler initialized')

    // Listen for plugin errors
    const handlePluginError = (event: CustomEvent) => {
      const { pluginName, error } = event.detail
      setAuthError(`Plugin ${pluginName} crashed: ${error}`)
    }

    window.addEventListener('plugin:error', handlePluginError as EventListener)

    // Preload critical routes after initial render
    const timer = setTimeout(preloadRoutes, 2000)

    return () => {
      window.removeEventListener('plugin:error', handlePluginError as EventListener)
      clearTimeout(timer)
    }
  }, [])

  // Helper function for authenticated requests
  function authFetch(url: string, options: RequestInit = {}) {
    const headers: Record<string, string> = {
      'Content-Type': 'application/json',
      'X-Requested-With': 'XMLHttpRequest', // CSRF protection
      ...(options.headers as Record<string, string> || {}),
    }

    if (apiKey) {
      headers['Authorization'] = `Bearer ${apiKey}`
    }

    // Ensure API URLs have the /api prefix
    const apiUrl = url.startsWith('/') && !url.startsWith('/api/') ? `/api${url}` : url
    return fetch(apiUrl, { ...options, headers })
  }

  function handleApiKeyChange(newKey: string) {
    setApiKey(newKey)
    localStorage.setItem('admin-api-key', newKey)
    setAuthError(null)
  }

  useEffect(() => {
    // Load plugins list
    ;(async () => {
      const res = await fetch('/api/plugins')
      setMarket(await res.json())
    })()
  }, [])

  // Register mount point when ref is available
  useEffect(() => {
    if (mountRef.current) {
      registerMountPoint('app:main', mountRef.current)
    }
  }, [mountRef.current])

  async function rescanPlugins() {
    try {
      setRescanLoading(true)
      setAuthError(null)
      const res = await authFetch('/admin/plugins/rescan', { method: 'POST' })
      if (!res.ok) {
        if (res.status === 401) {
          setAuthError('Authentication required. Please set your API key.')
          return
        }
        throw new Error(`HTTP ${res.status}`)
      }
      const pluginsRes = await fetch('/api/plugins')
      setMarket(await pluginsRes.json())
    } catch (e: any) {
      setAuthError(e?.message || 'Failed to rescan plugins')
    } finally {
      setRescanLoading(false)
    }
  }

  async function ensureMounted(item: MarketItem) {
    if (pluginUIs[item.name]) return

    // Ensure mount point is registered
    if (!mountRef.current) {
      console.warn('Mount point not ready yet, skipping plugin mount')
      return
    }

    try {
      const res = await fetch(item.manifest)
      const manifest: PluginManifest & { config?: any } = await res.json()
      const ui = await mountPlugin(manifest, 'app:main', {
        manifest,
        logger: console,
        events: eventBus,
        services: {},
        config: manifest.config ?? {},
      })
      if (typeof ui === 'function') setPluginUIs((prev) => ({ ...prev, [item.name]: ui as any }))
    } catch (error: any) {
      console.error(`Failed to mount plugin ${item.name}:`, error)
      setAuthError(`Failed to mount plugin ${item.name}: ${error.message}`)
    }
  }

  function ensureUnmounted(item: MarketItem) {
    if (!pluginUIs[item.name]) return
    setPluginUIs((prev) => {
      const next = { ...prev }
      delete next[item.name]
      return next
    })
  }

  useEffect(() => {
    if (!market.length || !mountRef.current) return
    ;(async () => {
      for (const item of market) {
        if (item.enabled) await ensureMounted(item)
        else ensureUnmounted(item)
      }
    })()
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [market, mountRef.current])

  async function toggleEnable(item: MarketItem) {
    try {
      setAuthError(null)
      const res = await authFetch(`/plugins/${encodeURIComponent(getIdFromName(item.name))}/` + (item.enabled ? 'disable' : 'enable'), {
        method: 'POST',
      })
      if (!res.ok) {
        if (res.status === 401) {
          setAuthError('Authentication required. Please set your API key.')
          return
        }
        throw new Error(`HTTP ${res.status}`)
      }
      const pluginsRes = await fetch('/api/plugins')
      setMarket(await pluginsRes.json())
    } catch (e: any) {
      setAuthError(e?.message || 'Failed to toggle plugin')
    }
  }

  async function openConfig(item: MarketItem) {
    try {
      setAuthError(null)
      const id = encodeURIComponent(getIdFromName(item.name))

      const [cfgRes, manRes] = await Promise.all([
        fetch(`/api/plugins/${id}/config`),
        fetch(`/api/plugins/${id}/manifest`),
      ])

      if (!cfgRes.ok) {
        throw new Error(`Failed to load config: HTTP ${cfgRes.status}`)
      }
      if (!manRes.ok) {
        throw new Error(`Failed to load manifest: HTTP ${manRes.status}`)
      }

      const data = await cfgRes.json()
      const manifest = await manRes.json()

      setFormValue(data)
      setFormSchema(manifest.configSchema || { type: 'object' })
      setEditing(item.name)
    } catch (e: any) {
      console.error('Failed to open config:', e)
      setAuthError(`Failed to open config: ${e.message}`)
    }
  }

  async function saveConfig(item: MarketItem) {
    try {
      setAuthError(null)
      const id = encodeURIComponent(getIdFromName(item.name))
      const res = await authFetch(`/plugins/${id}/config`, {
        method: 'POST',
        body: JSON.stringify(formValue),
      })
      if (!res.ok) {
        if (res.status === 401) {
          setAuthError('Authentication required. Please set your API key.')
          return
        }
        throw new Error(`HTTP ${res.status}`)
      }
      setEditing(null)
      const pluginsRes = await fetch('/api/plugins')
      setMarket(await pluginsRes.json())
    } catch (e: any) {
      setAuthError(e?.message || 'Failed to save config')
    }
  }

  function toggleTheme() {
    const next = theme === 'light' ? 'dark' : 'light'
    setTheme(next)
    eventBus.emit('theme:change', { theme: next })
  }

  // Apply theme to document
  useEffect(() => {
    document.documentElement.classList.toggle('dark', theme === 'dark')
  }, [theme])

  return (
    <ErrorBoundary>
      <Router>
        <Layout
          theme={theme}
          onThemeToggle={toggleTheme}
          apiKey={apiKey}
          onApiKeyChange={handleApiKeyChange}
          authError={authError}
        >
          <Suspense fallback={<LoadingSpinner text="Loading page..." />}>
            <Routes>
              <Route
                path="/"
                element={
                  <Dashboard
                    market={market}
                    pluginUIs={pluginUIs}
                    onTogglePlugin={toggleEnable}
                    onConfigurePlugin={openConfig}
                    onRescanPlugins={rescanPlugins}
                    rescanLoading={rescanLoading}
                    theme={theme}
                  />
                }
              />
              <Route
                path="/plugins"
                element={
                  <PluginManagement
                    market={market}
                    onTogglePlugin={toggleEnable}
                    onConfigurePlugin={openConfig}
                    onRescanPlugins={rescanPlugins}
                    rescanLoading={rescanLoading}
                  />
                }
              />
              <Route
                path="/plugins/:pluginId"
                element={
                  <PluginDetail
                    market={market}
                    pluginUIs={pluginUIs}
                    onTogglePlugin={toggleEnable}
                    onConfigurePlugin={openConfig}
                    theme={theme}
                  />
                }
              />
              <Route
                path="/admin"
                element={<AdminPanel authFetch={authFetch} />}
              />
              <Route
                path="/admin/audit"
                element={<AuditPage authFetch={authFetch} />}
              />
            </Routes>
          </Suspense>
      </Layout>

      {/* Configuration Modal */}
      <ConfigurationModal
        editing={editing}
        formSchema={formSchema}
        formValue={formValue}
        onFormChange={setFormValue}
        onSave={() => saveConfig(market.find((i) => i.name === editing)!)}
        onCancel={() => setEditing(null)}
      />

      {/* Hidden mount point for plugin registration */}
      <div ref={mountRef} id="plugin-mount-root" style={{ display: 'none' }} />
    </Router>
    </ErrorBoundary>
  )
}

